package cn.ivicar.app.controller.util;

import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.com.carsmart.exception.BadRequestException;
import cn.com.carsmart.exception.CarsmartException;

/**
 *  时间函数的格式化，时间差，获取今日最开始和最后的日期，日期差，获取日期类型，获取年、月、日，比较两个日期的大小，获取周和年，
 *  判断两个时间是否是在同一周，获取两个日期相差的分钟数，获取calendar中指定的日期是周几，根据制定的format,获取时间格式
 */
public class DateUtil {
	private static transient final Logger LOGGER = LoggerFactory.getLogger(DateUtil.class);

	/** 7 * 24 * 60 * 60 * 1000 毫秒 **/
	public static final long ONE_WEEK = 7 * 24 * 60 * 60 * 1000;

	/**
	 * 格式：HH:mm
	 */
	public static SimpleDateFormat getHHmm() {
		return new SimpleDateFormat("HH:mm");
	}

	/**
	 * 格式：yyyyMM
	 */
	public static SimpleDateFormat MONTHFORMATER() {
		return new SimpleDateFormat("yyyyMM");
	}

	/**
	 * 格式：yyyyMMdd
	 */
	public static SimpleDateFormat DATEFORMATER() {
		return new SimpleDateFormat("yyyyMMdd");
	}

	/**
	 * 格式：yyyy年MM月dd日
	 */
	public static SimpleDateFormat DATEFORMATER1() {
		return new SimpleDateFormat("yyyy年MM月dd日");
	}

	/**
	 * 格式：yyyy-MM-dd
	 */
	public static SimpleDateFormat DATEFORMATER2() {
		return new SimpleDateFormat("yyyy-MM-dd");
	}

	/**
	 * 格式：yyyy-MM
	 */
	public static SimpleDateFormat DATEFORMATER3() {
		return new SimpleDateFormat("yyyy-MM");
	}

	/**
	 * 格式：yyyy-MM-dd HH:mm:ss
	 */
	public static SimpleDateFormat TIMEFORMATER1() {
		return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	}

	/**
	 * 格式：yyyy-MM-dd HH:mm
	 */
	public static SimpleDateFormat TIMEFORMATER2() {
		return new SimpleDateFormat("yyyy-MM-dd HH:mm");
	}

	/**
	 * 格式：MM-dd HH:mm
	 */
	public static SimpleDateFormat TIMEFORMATER3() {
		return new SimpleDateFormat("MM-dd HH:mm");
	}

	public static Date formatTime1(String timeStr) throws CarsmartException {

		Date date;
		try {
			date = TIMEFORMATER1().parse(timeStr);
		} catch (Exception e) {
			String errorMsg = String.format("解析日期失败，非法的日期格式[%s], 正确格式为[yyyyMMdd-HH:mm:ss]", timeStr);
			LOGGER.trace(errorMsg);
			throw new BadRequestException("common", errorMsg);
		}

		return date;
	}

	/**
	  格式化时间
	  @param date
	  @return
	 */
	public static Date formatDate(Date date) {

		String dateString = DATEFORMATER().format(date);
		Date formatedDate = null;
		try {
			formatedDate = DATEFORMATER().parse(dateString);
		} catch (Exception e) {
			LOGGER.trace(e.getMessage());
			e.printStackTrace();
		}

		return formatedDate;
	}

	/**
	  参数的格式为:yyyyMM, 返回对应的日期类型
	  @param monthStr
	  @return
	  @throws CarsmartException
	 */
	public static Date formatMonth(String monthStr) throws CarsmartException {

		Date month;
		try {
			month = MONTHFORMATER().parse(monthStr);
		} catch (Exception e) {
			String errorMsg = String.format("解析月份失败，非法的月份格式[%s]", monthStr);
			LOGGER.trace(errorMsg);
			throw new BadRequestException("common", errorMsg);
		}

		return month;
	}

	/*
	  获取今天最开始时刻的日期对象
	  @param date
	  @return
	 */
	public static String stratTimeToday(Date date) {

		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.set(java.util.Calendar.HOUR_OF_DAY, 0);
		c.set(java.util.Calendar.MINUTE, 0);
		c.set(java.util.Calendar.SECOND, 0);

		return TIMEFORMATER1().format(c.getTime());
	}

	/*
	 获取今天最后时刻的日期对象
	  @param date
	  @return
	 */
	public static String endTimeToday(Date date) {

		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.set(java.util.Calendar.HOUR_OF_DAY, 23);
		c.set(java.util.Calendar.MINUTE, 59);
		c.set(java.util.Calendar.SECOND, 59);

		return TIMEFORMATER1().format(c.getTime());
	}

	/*
	 * 获取year年的第一天的日期
	  @param year
	  @return
	 */
	public static Date getStarDateByYear(int year) {
		Calendar c = Calendar.getInstance();
		c.set(Calendar.YEAR, year);
		c.set(Calendar.MONTH, 0);
		c.set(Calendar.DAY_OF_MONTH, 1);
		c.set(Calendar.HOUR_OF_DAY, 0);
		c.set(Calendar.MINUTE, 0);
		c.set(Calendar.SECOND, 0);
		c.set(Calendar.MILLISECOND, 0);
		return c.getTime();
	}

	/*
	 求两个日期差(忽略时分秒) endDate - beginDate
	  @param beginDate
	             开始日期
	  @param endDate
	             结束日期
	  @return 两个日期相差天数
	 */
	public static long getDateMargin2(Date beginDate, Date endDate) {
		long margin = 0;
		if (beginDate == null || endDate == null) {
			return margin;
		}
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		String b = df.format(beginDate);
		String e = df.format(endDate);
		try {
			long to = df.parse(e).getTime();
			long from = df.parse(b).getTime();
			margin = (to - from) / (1000 * 60 * 60 * 24);
		} catch (ParseException ignored) {
		}
		return margin;
	}

	/*
	 尝试转换 dateStr为日期类型, 如果formats为空, 则默认的日志格式为yyyy-MM-dd HH:mm:ss, yyyy-MM-dd,
	  如果转换失败则返回null.

	  @param dateStr
	             待尝试被转换的字符串
	  @param formats
	             使用的日期格式, 可以为null, 默认的格式为: yyyy-MM-dd, yyyy-MM-dd HH:mm:ss
	  @return 转换成功返回日期格式, 转换失败, 则返回null
	 */
	public static Date tryParseDate(String dateStr, SimpleDateFormat... formats) {
		if (StringUtils.isBlank(dateStr)) {
			return null;
		}
		dateStr = StringUtils.trim(dateStr);
		if (null == formats || formats.length == 0) {
			// yyyy-MM-dd, yyyy-MM-dd HH:mm:ss
			formats = new SimpleDateFormat[] { DATEFORMATER2(), TIMEFORMATER1() };
		}
		for (SimpleDateFormat format : formats) {
			try {
				return format.parse(dateStr);
			} catch (Exception e) {
				LOGGER.debug("尝试转换日期 [{0}]-> [{1}]时出错", new Object[] { dateStr, format });
			}
		}
		return null;
	}

	/*
	 获取date日期对应的年份
	 @param date
	 @return
	 */
	public static int getCalendarYear(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.get(Calendar.YEAR);
	}

	/*
	  根据时间戳, 获取月份
	  @param time
	  @return
	 */
	public static int getCalendarMonth(long time) {

		int month = 0;
		Calendar calendar = Calendar.getInstance();
		calendar.setTimeInMillis(time);
		month = calendar.get(Calendar.MONTH);
		return month + 1;
	}

	/*
	  根据时间戳, 获取为1-30天内的几号
	  @param time
	  @return
	 */
	public static int getCalendarDay(long time) {
		int day = 0;
		Calendar calendar = Calendar.getInstance();
		calendar.setTimeInMillis(time);
		day = calendar.get(Calendar.DAY_OF_MONTH);
		return day;
	}

	/*
	  获取month月的最后一天,结果中不包含时分秒 返回结果实例:2015-12-31
	  @param year
	  @param month
	  @return
	  @throws CarsmartException
	 */
	public static String getLastdayOfMonth(String year, String month) throws CarsmartException {
		try {
			Date date = formatMonth(year + month);
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			calendar.add(Calendar.MONTH, 1);
			calendar.set(Calendar.DAY_OF_MONTH, 0);
			return DATEFORMATER2().format(calendar.getTime());
		} catch (CarsmartException e) {
			e.printStackTrace();
			throw e;
		}
	}

	/*
	  使用format格式对日期进行格式化 注意:date为null,或者date的时间为1970-01-01, 返回null
	  @param date
	             待格式化的日期
	  @param format
	             格式化日期所使用的格式
	  @return (格式化失败) or (date is null) or (format is null) => null
	  @throws CarsmartException
	 */
	public static String formatDate(Date date, String format) throws CarsmartException {
		if (null == date || StringUtils.isBlank(format) || 0 == date.getTime())
			return null;
		SimpleDateFormat dateFormatter = getDateFormatter(format);
		if (null == dateFormatter)
			return null;
		return dateFormatter.format(date);
	}

	/*
	 使用format格式对日期进行格式化 注意:date为null, 或者date的时间为1970-01-01, 返回null
	  @param date
	             待格式化的日期
	  @param dateFormatter
	             格式化日期所使用的格式
	  @return (格式化失败) or (date is null) or (dateFormatter is null) => null
	  @throws CarsmartException
	 */
	public static String formatDate(Date date, SimpleDateFormat dateFormatter) throws CarsmartException {
		if (null == date || null == dateFormatter || 0 == date.getTime())
			return null;
		return dateFormatter.format(date);
	}

	/*
	  根据制定的format,获取时间格式 此方法会缓存参数中使用到的格式,避免重复创建 {@link SimpleDateFormat} 对象
	  @param format
	  @return
	 */
	public static SimpleDateFormat getDateFormatter(String format) {
		if (StringUtils.isBlank(format))
			return null;
		SimpleDateFormat dateFormat;
		try {
			dateFormat = new SimpleDateFormat(format);
		} catch (Exception e) {
			LOGGER.warn(MessageFormat.format("获取format[{0}]格式的SimpleDateFormat异常:", format), e);
			return null;
		}
		return dateFormat;
	}

	/*
	  @param fDate
	             为小日期,格式为yyyy-MM-dd HH:mm:ss;
	  @param sDate
	             为大日期,格式为yyyy-MM-dd HH:mm:ss;;
	  @date 2015年9月13日 下午5:44:05
	  @description 尝试比较两个为日期格式的字符串，不可以为空，格式为yyyy-MM-dd
	               HH:mm:ss,成功后返回true/fales,异常则返回null;
	 */
	public static Boolean tryCompareTime(String fDate, String sDate) {
		if (StringUtils.isBlank(fDate) || StringUtils.isBlank(sDate)) {
			return false;
		}
		Date fTime = null;
		Date sTime = null;
		try {
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			fTime = sdf.parse(fDate);
			sTime = sdf.parse(sDate);
		} catch (Exception e) {
			LOGGER.debug("时间转换异常！应为此格式：yyyy-MM-dd HH:mm:ss");
			return false;
		}
		if (fTime.before(sTime)) {
			return true;
		} else if (fTime.toString().equals(sTime.toString())) {
			return true;
		}
		return false;

	}

	/*
	  比较两个日期大小
	  @param dt1
	             时间1
	  @param dt2
	             时间2
	  @return 和compare遵循同样的规范
	  @throws CarsmartException
	 */
	public static int compareTime(Date dt1, Date dt2) throws CarsmartException {
		Integer flag = null;
		if (dt1.getTime() > dt2.getTime()) {
			flag = -1;
		} else if (dt1.getTime() < dt2.getTime()) {
			flag = 1;
		} else {
			flag = 0;
		}

		return flag;
	}

	public static Date getPreWeekStartDate(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		int weekDay = getWeekDay(calendar);
		calendar.add(Calendar.DAY_OF_YEAR, -(7 + weekDay - 1));
		return calendar.getTime();
	}

	public static Date getPreWeekEndDate(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.set(Calendar.HOUR_OF_DAY, 23);
		calendar.set(Calendar.MINUTE, 59);
		calendar.set(Calendar.SECOND, 59);
		int weekDay = getWeekDay(calendar);
		calendar.add(Calendar.DAY_OF_YEAR, -weekDay);
		return calendar.getTime();
	}

	/*
	  获取周和年

	  if 当前时间在第一个星期一之前 { if 第一个星期一位周日, 当前日期也为周日 then return 去年最后一天的周和年 else if
	  第一天为周一 then 周减一,年不变 else { if 当前时间在第一个周一之前 then return 去年最后一天的周和年 else if
	  当前时间在第一个周一的前一天 then 年为去年,周减一 else 周减一, 如果当天为周日, 还要减一 } } else {
	  先获取去年的最后一周是第几周 if 今年第一天不是周日 && 第一天在第一个周日之前 then 周减一 } 返回:new Integer[]
	  {周, 年}

	  @param date
	             比较的日期
	  @return new Integer[] {周, 年}
	  @throws CarsmartException
	 */
	public static Integer[] getWeekAndYear(Date date) throws CarsmartException {
		if (null == date)
			return null;
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);

		Calendar firstDayCalendar = Calendar.getInstance();
		int year = calendar.get(Calendar.YEAR);
		firstDayCalendar.setTime(getStarDateByYear(year));

		int week = calendar.get(Calendar.WEEK_OF_YEAR);
		int weekDay = getWeekDay(calendar);

		if (date.before(getLastMondayOfYear(year))) {
			if (7 == getWeekDay(firstDayCalendar)) {
				if (date.equals(firstDayCalendar.getTime())) {
					Calendar lastYearCalendar = Calendar.getInstance();
					lastYearCalendar.clear();
					lastYearCalendar.set(year - 1, Calendar.DECEMBER, 31);
					return getWeekAndYear(lastYearCalendar.getTime());
				} else if (7 == weekDay) {
					week--;
				}
			} else if (1 == getWeekDay(firstDayCalendar)) {
				if (7 == weekDay)
					week--;
			} else {
				Date firstMondayOfYear = getFirstMondayOfYear(year);
				Calendar firstMondayCalendar = Calendar.getInstance();
				firstMondayCalendar.setTime(getLastMondayOfYear(year));

				if (date.before(firstMondayOfYear)) {
					// week = getPreWeek(year-1) + 1;
					// year --;
					Calendar lastYearCalendar = Calendar.getInstance();
					lastYearCalendar.clear();
					lastYearCalendar.set(year - 1, Calendar.DECEMBER, 31);
					return getWeekAndYear(lastYearCalendar.getTime());
				} else if (firstMondayCalendar.get(Calendar.DAY_OF_YEAR) - calendar.get(Calendar.DAY_OF_YEAR) == 1) {
					calendar.add(Calendar.DAY_OF_YEAR, -1);
					week = calendar.get(Calendar.WEEK_OF_YEAR);
					week--;
				} else {
					week--;
					if (7 == weekDay)
						week--;
				}
			}
		} else/* if (!date.before(getLastMondayOfYear(year))) */ {
			week = getPreWeek(year) + 1;
			if (7 != getWeekDay(firstDayCalendar) && firstDayCalendar.getTime().before(getFirstMondayOfYear(year))) {
				week--;
			}
		}

		return new Integer[] { week, year };
	}

	private static int getPreWeek(int year) {
		Date lastMondayOfYear = getLastMondayOfYear(year);
		Calendar calendar1 = Calendar.getInstance();
		calendar1.setTime(lastMondayOfYear);
		calendar1.add(Calendar.DAY_OF_YEAR, -2);
		return calendar1.get(Calendar.WEEK_OF_YEAR);
	}

	/*
	  获取年{@code year}中的第一个星期一的日期
	  @param year
	             年份
	  @return
	 */
	public static Date getFirstMondayOfYear(int year) {
		Calendar calendar = Calendar.getInstance();
		calendar.clear();
		calendar.set(Calendar.YEAR, year);
		int weekDay = getWeekDay(calendar);
		if (1 == weekDay) {
			return calendar.getTime();
		} else {
			calendar.add(Calendar.DAY_OF_YEAR, 8 - weekDay);
			return calendar.getTime();
		}
	}

	/*
	  获取年{@code year}中的最后一个星期一的日期
	  @param year
	             年份
	 @return
	 */
	public static Date getLastMondayOfYear(int year) {
		Calendar calendar = Calendar.getInstance();
		calendar.clear();
		calendar.set(Calendar.YEAR, year + 1);
		calendar.add(Calendar.DAY_OF_YEAR, -1);
		int weekDay = getWeekDay(calendar);
		calendar.add(Calendar.DAY_OF_YEAR, -(weekDay - 1));
		return calendar.getTime();
	}

	/*
	  获取calendar中指定的日期是周几 注意: 和Calendar中的周几不同, 返回1为周一, 7为周日
	  @param calendar
	  @return
	 */
	public static int getWeekDay(Calendar calendar) {
		int weekDay = calendar.get(Calendar.DAY_OF_WEEK);

		boolean sundayIsFirstDay = calendar.getFirstDayOfWeek() == Calendar.SUNDAY;
		if (sundayIsFirstDay) {
			weekDay--;
			if (0 == weekDay) {
				weekDay = 7;
			}
		}
		return weekDay;
	}

	/*
	  获取long类型的日期, 如果date==null, 或者date为1970年的日期, 则返回空串, 其它情况, 返回long+""的形式
	  @param date
	  @return
	 */
	public static String getLongDate(Date date) {
		if (null == date || 0 == date.getTime())
			return "";
		return date.getTime() + "";
	}

	/*
	  获取两个日期相差的分钟数
	  @param beginDate
	  @param endDate
	  @return
	 */
	public static long getDateDiffByMInutes(Date beginDate, Date endDate) {
		long margin = 0;
		if (beginDate == null || endDate == null) {
			return margin;
		}
		margin = endDate.getTime() - beginDate.getTime();
		return margin / (1000 * 60);
	}

	/*
	  判断两个时间是否是在同一周(以星期一作为一周的开始)
	  @param time1
	  @param time2
	  @return
	 */
	public static boolean validateSameWeek(long time1, long time2) {
		boolean flag = false;
		long time = Math.abs(time1 - time2);
		if (time > ONE_WEEK) {
			return false;
		}
		Calendar calendar1 = Calendar.getInstance();
		calendar1.setTimeInMillis(time1);
		calendar1.setFirstDayOfWeek(Calendar.MONDAY);
		int week1 = calendar1.get(Calendar.WEEK_OF_YEAR);
		calendar1.setTimeInMillis(time2);
		int week2 = calendar1.get(Calendar.WEEK_OF_YEAR);
		if (week1 == week2) {
			flag = true;
		}
		return flag;
	}

	public static boolean validateSameDay(long time1, long time2) {
		boolean flag = false;

		Calendar calendar1 = Calendar.getInstance();
		calendar1.setTimeInMillis(time1);
		calendar1.set(Calendar.HOUR_OF_DAY, 0);
		calendar1.set(Calendar.MINUTE, 0);
		calendar1.set(Calendar.SECOND, 0);
		calendar1.add(Calendar.DATE, 1);
		long end = calendar1.getTimeInMillis();
		calendar1.add(Calendar.DATE, -2);
		calendar1.set(Calendar.HOUR_OF_DAY, 23);
		calendar1.set(Calendar.MINUTE, 59);
		calendar1.set(Calendar.SECOND, 59);
		long start = calendar1.getTimeInMillis();

		if (time2 > start && time2 < end) {
			flag = true;
		}

		return flag;
	}
}
